package com.almeros.ohos.multitouch.library;

import ohos.multimodalinput.event.TouchEvent;

import java.math.BigDecimal;

/**
 * @author Almer Thie (code.almeros.com)
 * Copyright (c) 2013, Almer Thie (code.almeros.com)
 * <p>
 * All rights reserved.
 * <p>
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 * <p>
 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the distribution.
 * <p>
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 */
public class RotateGestureDetector {

    private static final int INVALID_POINTER_INDEX = -1;

    private float fX, fY, sX, sY;

    private int mPointerIndex1, mPointerIndex2;
    private float mAngle;

    private OnRotationGestureListener mListener;

    public RotateGestureDetector(OnRotationGestureListener listener) {
        mListener = listener;
        mPointerIndex1 = INVALID_POINTER_INDEX;
        mPointerIndex2 = INVALID_POINTER_INDEX;
    }

    public float getAngle() {
        return mAngle;
    }

    public boolean onTouchEvent(TouchEvent event) {
        switch (event.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                sX = event.getPointerPosition(0).getX();
                sY = event.getPointerPosition(0).getY();
                mPointerIndex1 = event.getPointerId(0);
                break;
            case TouchEvent.OTHER_POINT_DOWN:
                fX = event.getPointerPosition(0).getX();
                fY = event.getPointerPosition(0).getY();
                mPointerIndex2 = event.getPointerId(event.getIndex());
                break;
            case TouchEvent.POINT_MOVE:
                if (mPointerIndex1 != INVALID_POINTER_INDEX && mPointerIndex2 != INVALID_POINTER_INDEX && event.getPointerCount() > mPointerIndex2) {
                    float nfX, nfY, nsX, nsY;

                    nsX = event.getPointerPosition(mPointerIndex1).getX();
                    nsY = event.getPointerPosition(mPointerIndex1).getY();
                    nfX = event.getPointerPosition(mPointerIndex2).getX();
                    nfY = event.getPointerPosition(mPointerIndex2).getY();

                    calculateAngleBetweenLines(fX, fY, sX, sY, nfX, nfY, nsX, nsY);

                    if (mListener != null) {
                        mListener.onRotation(this);
                    }
                    BigDecimal bignum1 = new BigDecimal(fY);
                    BigDecimal bignum2 = new BigDecimal(nfY);
                    BigDecimal bignum3 = new BigDecimal(sY);
                    BigDecimal bignum4 = new BigDecimal(nsY);
                    if (Math.abs(bignum1.subtract(bignum2).floatValue()) > 50 ||
                            Math.abs(bignum3.subtract(bignum4).floatValue()) > 50) {
                        fX = nfX;
                        fY = nfY;
                        sX = nsX;
                        sY = nsY;
                    }
                }
                break;
            case TouchEvent.PRIMARY_POINT_UP:
                mPointerIndex1 = INVALID_POINTER_INDEX;
                break;
            case TouchEvent.OTHER_POINT_UP:
                mPointerIndex2 = INVALID_POINTER_INDEX;
                break;
        }
        return true;
    }

    private void calculateAngleBetweenLines(float fx1, float fy1, float fx2, float fy2,
                                            float sx1, float sy1, float sx2, float sy2) {
        clockwise(sy1, sy2);
        anticlockwise(sy1, sy2);
    }

    private void clockwise(float nfY, float nsY) {
        BigDecimal bignum1 = new BigDecimal(fY);
        BigDecimal bignum2 = new BigDecimal(nfY);
        BigDecimal bignum3 = new BigDecimal(sY);
        BigDecimal bignum4 = new BigDecimal(nsY);
        float value = bignum1.subtract(bignum2).floatValue();
        float value2 = bignum3.subtract(bignum4).floatValue();
        //顺时针旋转
        if (sX > fX) {//第一个手指在右，第二个手指在左
            if ((fY > nfY && sY < nsY)) {
                if (Math.abs(value) > 50 || Math.abs(value2) > 50) {
                    if (mAngle == 360) {
                        mAngle = 0;
                    }
                    BigDecimal bignum5 = new BigDecimal(mAngle);
                    BigDecimal bignum6 = new BigDecimal(10);
                    mAngle = bignum5.add(bignum6).floatValue();
                }
            }
        }
        if (sX < fX) {//第一个手指在左，第二个手指在右
            if ((fY < nfY && sY > nsY)) {
                if (Math.abs(value) > 50 || Math.abs(value2) > 50) {
                    if (mAngle == 360) {
                        mAngle = 0;
                    }
                    BigDecimal bignum5 = new BigDecimal(mAngle);
                    BigDecimal bignum6 = new BigDecimal(10);
                    mAngle = bignum5.add(bignum6).floatValue();
                }
            }
        }
    }

    private void anticlockwise(float nfY, float nsY) {
        BigDecimal bignum1 = new BigDecimal(fY);
        BigDecimal bignum2 = new BigDecimal(nfY);
        BigDecimal bignum3 = new BigDecimal(sY);
        BigDecimal bignum4 = new BigDecimal(nsY);
        float value = bignum1.subtract(bignum2).floatValue();
        float value2 = bignum3.subtract(bignum4).floatValue();
        //逆时针旋转
        if (sX > fX) {//第一个手指在右，第二个手指在左
            if ((fY < nfY && sY > nsY)) {
                if (Math.abs(value) > 50 || Math.abs(value2) > 50) {
                    if (mAngle == -360) {
                        mAngle = 0;
                    }
                    BigDecimal bignum5 = new BigDecimal(mAngle);
                    BigDecimal bignum6 = new BigDecimal(10);
                    mAngle = bignum5.subtract(bignum6).floatValue();
                }
            }
        }
        if (sX < fX) {//第一个手指在左，第二个手指在右
            if ((fY > nfY && sY < nsY)) {
                if (Math.abs(value) > 50 || Math.abs(value2) > 50) {
                    if (mAngle == -360) {
                        mAngle = 0;
                    }
                    BigDecimal bignum5 = new BigDecimal(mAngle);
                    BigDecimal bignum6 = new BigDecimal(10);
                    mAngle = bignum5.subtract(bignum6).floatValue();
                }
            }
        }
    }

    public static class SimpleOnRotationGestureListener implements OnRotationGestureListener {

        @Override
        public boolean onRotation(RotateGestureDetector rotationDetector) {
            return false;
        }
    }

    public interface OnRotationGestureListener {

        boolean onRotation(RotateGestureDetector rotationDetector);
    }
}
